package game;

import java.util.Random;

import be.kuleuven.cs.som.annotate.Basic;

import values.Vector;

public class Asteroid extends SpaceObject {

	public static final double DENSITY = 2.65*Math.pow(10, 12);
	private final Random velocityDirectionGenerator;
	
	public Asteroid(double xPosition, double yPosition, double xVelocity, double yVelocity, double radius, double maxVelocity, World world) {
		super(xPosition, yPosition, xVelocity, yVelocity, radius, maxVelocity, world);
		this.velocityDirectionGenerator = new Random();
		
	}
	
	public Asteroid(double x, double y, double xVelocity, double yVelocity,
			double radius, double maxVelocity, World world, Random random) {
		super(x, y, xVelocity, yVelocity, radius, maxVelocity, world);
		this.velocityDirectionGenerator = random;
	}

	public double calculateMass() {
		return 4.0/3.0*Math.pow(getRadius(), 3)*Math.PI*Asteroid.DENSITY;
	}
	
	/**
	 * 
	 */
	@Override
	public void collideWith(SpaceObject otherObject) throws IllegalArgumentException, IllegalStateException {
		super.collideWith(otherObject);
		if(otherObject instanceof Ship) {
			otherObject.terminate();
		}
		else if(otherObject instanceof Asteroid) {
			this.bounce((Asteroid) otherObject);
		}
		else if(otherObject instanceof Bullet) {
				otherObject.terminate();
				this.terminate();
		}
		else 
			throw new IllegalArgumentException();
	}
	
	/**
	 * This asteroid breaks into two smaller asteroids.
	 * @effect	| if(getRadius >= 30 && isInWorld()) { this.getWorld().addSpaceObject(...) && ... }
	 * 
	 */
	public void breakIntoSmallAsteroids() {
		if(getRadius() < 30 || ! isInWorld()) return;
		Vector newVelocity = new Vector(getVelocityLength()*1.5,getVelocityDirectionGenerator().nextDouble()*2.0*Math.PI,true);
		new Asteroid(getxPosition()-getRadius()/2.0, getyPosition(), newVelocity.getxComp(), newVelocity.getyComp(), getRadius()/2, getMaxVelocity(), getWorld());
		new Asteroid(getxPosition()+getRadius()/2.0, getyPosition(), -newVelocity.getxComp(), -newVelocity.getyComp(), getRadius()/2, getMaxVelocity(), getWorld());
	}
	
	/**
	 * 
	 * @return
	 */
	@Basic
	public Random getVelocityDirectionGenerator() {
		return this.velocityDirectionGenerator;
	}

	/**
	 * 
	 */
	@Override
	public void terminate() {
		breakIntoSmallAsteroids();
		super.terminate();
	}
	
	/**
	 * This asteroid bounces off the given other asteroid.
	 * @post	Impulse before and after bounce is constant.
	 * 			| (new this).getVelocity()*this.calculateMass()+(new otherAsteroid).getVelocity()*otherAsteroid.calculateMass() == 
	 * 			| 	this.getVelocity()*this.calculateMass()+ otherAsteroid.getVelocity()*otherAsteroid.calculateMass()
	 */
	public void bounce(Asteroid otherAsteroid) {
		Vector deltaR = (otherAsteroid.getPosition()).subtract(this.getPosition());
		Vector deltaV = (otherAsteroid.getVelocity()).subtract(this.getVelocity());
		double dVdR = deltaR.scalarProduct(deltaV);
		double sigma = this.getRadius()+otherAsteroid.getRadius();
		
		double J = 2*this.calculateMass()*otherAsteroid.calculateMass()*dVdR/(sigma*(this.calculateMass()+otherAsteroid.calculateMass()));
		double Jx = J*deltaR.getxComp()/sigma;
		double Jy = J*deltaR.getyComp()/sigma;
		
		this.setVelocity(getxVelocity()+Jx/calculateMass(), getyVelocity()+Jy/calculateMass());
		otherAsteroid.setVelocity(otherAsteroid.getxVelocity()-Jx/otherAsteroid.calculateMass(), otherAsteroid.getyVelocity()-Jy/otherAsteroid.calculateMass());
	}
}
